/*
 * Powered By newdev
 * Since 2020
 */

package com.xy.biz.uc.client;

import com.xy.biz.uc.domain.dto.UserDTO;
import com.xy.biz.uc.domain.req.*;
import com.xy.biz.uc.domain.resp.SaveUserResponse;
import com.xy.lang.domain.Result;
import com.xy.lang.util.CollectionUtilsEx;
import com.xy.lang.util.ResultUtils;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.xy.biz.uc.domain.constant.RoleConstant.SALES;

/**
 *
 *
 * @author zsp
 * @date 2020-6-11
 */
public interface UserClient {

    /**
     * 保存
     *
     * @param request
     * @return
     */
    Result<SaveUserResponse> saveUserByUserCode(SaveUserRequest request);

    /**
     * 保存
     *
     * @param request
     * @return
     */
    Result<SaveUserResponse> saveUserByMobile(SaveUserRequest request);

    /**
     * 保存
     *
     * @param request
     * @return
     */
    Result<SaveUserResponse> saveUserByEmail(SaveUserRequest request);

    /**
     * 查找一个
     *
     * @param request
     * @return
     */
    Result<UserDTO> getUserByUserCode(GetUserByUserCodeRequest request);

    /**
     * 修改文件基本信息
     */
    Result<?> updateUserBaseInfo(SaveUserRequest request);

    Result<UserDTO> getUser(GetUserRequest request);

    /**
     * 判断是否有权限（销售页面）
     */
    Result<Boolean> hasPermission();

    /**
     * 判断当前用户是否具有指定的角色
     *
     * @param request                请求
     * @return 返回true表示具有，否则返回false表示不具有。
     */
    Result<Boolean> isInRole(IsInRoleRequest request);

    /**
     * 是否属于唯一角色
     *
     * @param includeRoleCode              包括的角色编号
     * @return
     */
    default boolean isOnlyOneRole(String includeRoleCode) {
        return ResultUtils.get(isInRole(IsInRoleRequest.builder()
                .includeRoleCodeList(Arrays.asList(includeRoleCode))
                .ownership(IsInRoleRequest.Ownership.ONLY_ONE_ROLE.getCode())
                .build()));
    }

    /**
     * 是否具有指定的角色
     *
     * @param includeRoleCode              包括的角色编号
     * @param excludeRoleCodeCollection    不包括的角色编号
     * @return
     */
    default boolean isOneInRole(String includeRoleCode, Collection<String> excludeRoleCodeCollection) {
        return ResultUtils.get(isInRole(IsInRoleRequest.builder()
                .includeRoleCodeList(Arrays.asList(includeRoleCode))
                .excludeRoleCodeList(CollectionUtilsEx.isEmpty(excludeRoleCodeCollection)
                        ? Collections.emptyList() : excludeRoleCodeCollection.stream().collect(Collectors.toList()))
                .ownership(IsInRoleRequest.Ownership.ONE_IN_ROLE.getCode())
                .build()));
    }

    /**
     * 是否具有全部指定的角色
     *
     * @param includeRoleCodeCollection    包括的角色编号
     * @param excludeRoleCodeCollection    不包括的角色编号
     * @return
     */
    default boolean isAllInRole(Collection<String> includeRoleCodeCollection, Collection<String> excludeRoleCodeCollection) {
        return ResultUtils.get(isInRole(IsInRoleRequest.builder()
                .includeRoleCodeList(CollectionUtilsEx.isEmpty(includeRoleCodeCollection)
                        ? Collections.emptyList() : includeRoleCodeCollection.stream().collect(Collectors.toList()))
                .excludeRoleCodeList(CollectionUtilsEx.isEmpty(excludeRoleCodeCollection)
                        ? Collections.emptyList() : excludeRoleCodeCollection.stream().collect(Collectors.toList()))
                .ownership(IsInRoleRequest.Ownership.ALL_IN_ROLE.getCode())
                .build()));
    }

    /**
     * 是否具有至少一个指定的角色
     *
     * @param includeRoleCodeCollection    包括的角色编号
     * @param excludeRoleCodeCollection    不包括的角色编号
     * @return
     */
    default boolean isOneInRole(Collection<String> includeRoleCodeCollection, Collection<String> excludeRoleCodeCollection) {
        return ResultUtils.get(isInRole(IsInRoleRequest.builder()
                .includeRoleCodeList(CollectionUtilsEx.isEmpty(includeRoleCodeCollection)
                        ? Collections.emptyList() : includeRoleCodeCollection.stream().collect(Collectors.toList()))
                .excludeRoleCodeList(CollectionUtilsEx.isEmpty(excludeRoleCodeCollection)
                        ? Collections.emptyList() : excludeRoleCodeCollection.stream().collect(Collectors.toList()))
                .ownership(IsInRoleRequest.Ownership.ONE_IN_ROLE.getCode())
                .build()));
    }

    /**
     * 根据名字返回用户信息
     */
    Result<UserDTO> getUserByUserName(GetUserByNameRequest request);

    Result<List<UserDTO>> getUserByUserNameS(Collection<String> collection);

    Result<List<UserDTO>> listUserByUserGroup(ListUserGroupByIdsRequest request);

    Result<List<UserDTO>> listUser(ListUserRequest request);

    /**
     *
     * @param collection
     * @return
     */
    Result<List<UserDTO>> listUserById(Collection<Long> collection);

    /**
     * 通过用户组id获取用户id列表
     * @param collection
     * @return
     */
    Result<Collection<Long>> listUserIdByUserGroupId(Collection<Long> collection);

    /**
     * 构建用户名称
     * @param source 需要构建的集合
     * @param userIdCollection 需要构建的集合提取的用户id列表
     * @param userIdGetter 内部便利每次获取的用户id
     * @param builder 赋值函数
     * @param <T>
     */
    default <T> void buildByUser(Collection<T> source,
                                 Collection<Long> userIdCollection,
                                 Function<T, Long> userIdGetter,
                                 BiConsumer<T, UserDTO> builder) {
        Objects.requireNonNull(userIdGetter, "The userIdGetter is required.");
        Objects.requireNonNull(builder, "The builder is required.");
        if (source == null || source.size() == 0) {
            return;
        }
        if (userIdCollection == null || userIdCollection.size() == 0) {
            return;
        }
        Set<Long> userIdSet = new HashSet<>(userIdCollection);
        List<UserDTO> userDTOList = ResultUtils.get(listUserById(userIdSet));
        if (userDTOList != null && userDTOList.size() > 0) {
            Map<Long, UserDTO> userDTOMap = userDTOList.stream().collect(Collectors.toMap(UserDTO::getUserId, e -> e));
            UserDTO userDTO;
            Long userId;
            for (T entity : source) {
                userId = userIdGetter.apply(entity);
                userDTO = userDTOMap.get(userId);
                if (userDTO != null) {
                    builder.accept(entity, userDTO);
                }
            }
        }
    }

}
